## importing the necessary libraries
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import pathlib
from tensorflow.keras import models, layers # Import models and layers from Keras
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
from tensorflow.keras.optimizers import RMSprop # Import RMSprop optimizer
from tensorflow.keras.applications.vgg16 import preprocess_input
from tensorflow.keras.applications import VGG16
### loading the dataset
import os, shutil, pathlib
original_dir = pathlib.Path(r"C:\Users\PC\Documents\CSCN8010\CSCN8010-labs\data\train\train")
new_base_dir = pathlib.Path("../data/kaggle_dogs_vs_cats_small")
def make_subset(subset_name, start_index, end_index):
for category in ("cat", "dog"):
dir = new_base_dir / subset_name / category
os.makedirs(dir, exist_ok=True)
fnames = [f"{category}.{i}.jpg" for i in range(start_index, end_index)]
for fname in fnames:
shutil.copyfile(src=original_dir / fname,
dst=dir / fname)
make_subset("train", start_index=0, end_index=1000)
make_subset("validation", start_index=1000, end_index=1500)
make_subset("test", start_index=1500, end_index=2500)
### loading the dataset
data_folder = pathlib.Path('../data/kaggle_dogs_vs_cats_small')
### splitting the data into different classes
from tensorflow.keras.utils import image_dataset_from_directory
train_dataset = image_dataset_from_directory(
data_folder / "train",
image_size=(180, 180),
batch_size=32)
validation_dataset = image_dataset_from_directory(
data_folder / "validation",
image_size=(180, 180),
batch_size=32)
test_dataset = image_dataset_from_directory(
data_folder / "test",
image_size=(180, 180),
batch_size=32)
Found 2000 files belonging to 2 classes. Found 1000 files belonging to 2 classes. Found 2000 files belonging to 2 classes.
# Inspect the dataset structure
for images, labels in train_dataset.take(1):
print("Images shape:", images.shape)
print("Labels shape:", labels.shape)
Images shape: (32, 180, 180, 3) Labels shape: (32,)
type(train_dataset)
tensorflow.python.data.ops.batch_op._BatchDataset
from collections import Counter
## checking data structure and class distribution
# Count the number of samples per class in each dataset
def count_classes(dataset):
class_counts = Counter()
for _, labels in dataset:
class_counts.update(labels.numpy().tolist())
return class_counts
# Analyze class distribution
train_class_counts = count_classes(train_dataset)
val_class_counts = count_classes(validation_dataset)
test_class_counts = count_classes(test_dataset)
print("Class distribution in training set:", train_class_counts)
print("Class distribution in validation set:", val_class_counts)
print("Class distribution in test set:", test_class_counts)
# Visualize class distribution
import matplotlib.pyplot as plt
labels = ['Cat', 'Dog']
train_counts = [train_class_counts[0], train_class_counts[1]]
val_counts = [val_class_counts[0], val_class_counts[1]]
test_counts = [test_class_counts[0], test_class_counts[1]]
plt.figure(figsize=(12, 6))
plt.bar(labels, train_counts, label='Train', alpha=0.6)
plt.bar(labels, val_counts, label='Validation', alpha=0.6)
plt.bar(labels, test_counts, label='Test', alpha=0.6)
plt.title("Class Distribution Across Train, Validation, and Test Sets")
plt.ylabel("Number of Samples")
plt.legend()
plt.show()
Class distribution in training set: Counter({1: 1000, 0: 1000})
Class distribution in validation set: Counter({0: 500, 1: 500})
Class distribution in test set: Counter({1: 1000, 0: 1000})
import numpy as np
## visualizing sample images from dataset
# Visualize a few sample images
for images, labels in train_dataset.take(1):
plt.figure(figsize=(12, 12))
for i in range(9): # Show 9 images
ax = plt.subplot(3, 3, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title("Cat" if labels[i] == 0 else "Dog")
plt.axis("off")
break
# Analyzing image shapes and pixel intensity ranges
# Analyze image shapes
for images, _ in train_dataset.take(1): # Take one batch
print("Image batch shape:", images.shape) # Should be (batch_size, height, width, channels)
# Analyze pixel intensity range
for images, _ in train_dataset.take(1):
pixel_values = images.numpy().ravel()
print("Min pixel value:", pixel_values.min())
print("Max pixel value:", pixel_values.max())
print("Mean pixel value:", pixel_values.mean())
print("Std pixel value:", pixel_values.std())
break
# Plot histogram of pixel intensities
plt.figure(figsize=(8, 6))
plt.hist(pixel_values, bins=50, color="blue", alpha=0.7)
plt.title("Pixel Intensity Distribution")
plt.xlabel("Pixel Value")
plt.ylabel("Frequency")
plt.show()
Image batch shape: (32, 180, 180, 3) Min pixel value: 0.0 Max pixel value: 255.0 Mean pixel value: 112.782 Std pixel value: 64.51781
# Visualize dataset balance for training, validation, and test sets
data_splits = ["Train", "Validation", "Test"]
counts = [train_counts, val_counts, test_counts]
plt.figure(figsize=(10, 6))
for i, split in enumerate(data_splits):
plt.bar([f"{split} - Cat", f"{split} - Dog"], [counts[i][0], counts[i][1]])
plt.title("Dataset Balance Across Splits")
plt.ylabel("Number of Samples")
plt.show()
inputs = keras.Input(shape=(180, 180, 3))
x = layers.Rescaling(1./255)(inputs)
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.Flatten()(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
## statistical summary of the model
model.summary()
Model: "model_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_3 (InputLayer) [(None, 180, 180, 3)] 0
rescaling_2 (Rescaling) (None, 180, 180, 3) 0
conv2d_10 (Conv2D) (None, 178, 178, 32) 896
max_pooling2d_8 (MaxPooling (None, 89, 89, 32) 0
2D)
conv2d_11 (Conv2D) (None, 87, 87, 64) 18496
max_pooling2d_9 (MaxPooling (None, 43, 43, 64) 0
2D)
conv2d_12 (Conv2D) (None, 41, 41, 128) 73856
max_pooling2d_10 (MaxPoolin (None, 20, 20, 128) 0
g2D)
conv2d_13 (Conv2D) (None, 18, 18, 256) 295168
max_pooling2d_11 (MaxPoolin (None, 9, 9, 256) 0
g2D)
conv2d_14 (Conv2D) (None, 7, 7, 256) 590080
flatten_4 (Flatten) (None, 12544) 0
dense_10 (Dense) (None, 1) 12545
=================================================================
Total params: 991,041
Trainable params: 991,041
Non-trainable params: 0
_________________________________________________________________
model.compile(loss="binary_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
## saving best model in a callback before data augumentation
callbacks = [
keras.callbacks.ModelCheckpoint(
filepath="./models/convnet_from_scratch.keras",
save_best_only= True,
monitor="val_loss")
]
history = model.fit(
train_dataset,
epochs=30,
validation_data=validation_dataset,
callbacks=callbacks)
Epoch 1/30 63/63 [==============================] - 121s 2s/step - loss: 0.6975 - accuracy: 0.5150 - val_loss: 0.6934 - val_accuracy: 0.5000 Epoch 2/30 63/63 [==============================] - 120s 2s/step - loss: 0.6970 - accuracy: 0.5255 - val_loss: 0.6890 - val_accuracy: 0.5080 Epoch 3/30 63/63 [==============================] - 150s 2s/step - loss: 0.6774 - accuracy: 0.5865 - val_loss: 0.6920 - val_accuracy: 0.5470 Epoch 4/30 63/63 [==============================] - 141s 2s/step - loss: 0.6480 - accuracy: 0.6190 - val_loss: 0.6458 - val_accuracy: 0.6430 Epoch 5/30 63/63 [==============================] - 138s 2s/step - loss: 0.6308 - accuracy: 0.6565 - val_loss: 0.6297 - val_accuracy: 0.6330 Epoch 6/30 63/63 [==============================] - 119s 2s/step - loss: 0.5873 - accuracy: 0.6885 - val_loss: 0.6555 - val_accuracy: 0.5900 Epoch 7/30 63/63 [==============================] - 128s 2s/step - loss: 0.5496 - accuracy: 0.7220 - val_loss: 0.5827 - val_accuracy: 0.7000 Epoch 8/30 63/63 [==============================] - 148s 2s/step - loss: 0.4995 - accuracy: 0.7545 - val_loss: 0.6925 - val_accuracy: 0.6670 Epoch 9/30 63/63 [==============================] - 155s 2s/step - loss: 0.4593 - accuracy: 0.7880 - val_loss: 0.6995 - val_accuracy: 0.6740 Epoch 10/30 63/63 [==============================] - 138s 2s/step - loss: 0.4230 - accuracy: 0.8075 - val_loss: 0.5822 - val_accuracy: 0.7290 Epoch 11/30 63/63 [==============================] - 136s 2s/step - loss: 0.3609 - accuracy: 0.8375 - val_loss: 0.6129 - val_accuracy: 0.7240 Epoch 12/30 63/63 [==============================] - 128s 2s/step - loss: 0.3034 - accuracy: 0.8735 - val_loss: 0.6826 - val_accuracy: 0.7320 Epoch 13/30 63/63 [==============================] - 120s 2s/step - loss: 0.2356 - accuracy: 0.9085 - val_loss: 0.7413 - val_accuracy: 0.6820 Epoch 14/30 63/63 [==============================] - 123s 2s/step - loss: 0.1862 - accuracy: 0.9335 - val_loss: 1.0184 - val_accuracy: 0.6900 Epoch 15/30 63/63 [==============================] - 119s 2s/step - loss: 0.1428 - accuracy: 0.9410 - val_loss: 1.1254 - val_accuracy: 0.7230 Epoch 16/30 63/63 [==============================] - 119s 2s/step - loss: 0.1257 - accuracy: 0.9500 - val_loss: 1.2745 - val_accuracy: 0.7170 Epoch 17/30 63/63 [==============================] - 119s 2s/step - loss: 0.0991 - accuracy: 0.9675 - val_loss: 1.4149 - val_accuracy: 0.7110 Epoch 18/30 63/63 [==============================] - 120s 2s/step - loss: 0.0851 - accuracy: 0.9720 - val_loss: 1.5761 - val_accuracy: 0.6860 Epoch 19/30 63/63 [==============================] - 125s 2s/step - loss: 0.0667 - accuracy: 0.9750 - val_loss: 1.5752 - val_accuracy: 0.7010 Epoch 20/30 63/63 [==============================] - 118s 2s/step - loss: 0.0790 - accuracy: 0.9770 - val_loss: 1.5237 - val_accuracy: 0.7070 Epoch 21/30 63/63 [==============================] - 120s 2s/step - loss: 0.0591 - accuracy: 0.9835 - val_loss: 1.5554 - val_accuracy: 0.7180 Epoch 22/30 63/63 [==============================] - 127s 2s/step - loss: 0.0445 - accuracy: 0.9880 - val_loss: 1.6306 - val_accuracy: 0.7100 Epoch 23/30 63/63 [==============================] - 118s 2s/step - loss: 0.0492 - accuracy: 0.9820 - val_loss: 1.9960 - val_accuracy: 0.6970 Epoch 24/30 63/63 [==============================] - 119s 2s/step - loss: 0.0464 - accuracy: 0.9845 - val_loss: 1.8086 - val_accuracy: 0.7250 Epoch 25/30 63/63 [==============================] - 120s 2s/step - loss: 0.0705 - accuracy: 0.9890 - val_loss: 1.7880 - val_accuracy: 0.7220 Epoch 26/30 63/63 [==============================] - 118s 2s/step - loss: 0.0594 - accuracy: 0.9820 - val_loss: 2.0587 - val_accuracy: 0.7140 Epoch 27/30 63/63 [==============================] - 119s 2s/step - loss: 0.0382 - accuracy: 0.9890 - val_loss: 2.2545 - val_accuracy: 0.7100 Epoch 28/30 63/63 [==============================] - 119s 2s/step - loss: 0.0391 - accuracy: 0.9890 - val_loss: 2.3877 - val_accuracy: 0.6960 Epoch 29/30 63/63 [==============================] - 117s 2s/step - loss: 0.0348 - accuracy: 0.9885 - val_loss: 2.3350 - val_accuracy: 0.7190 Epoch 30/30 63/63 [==============================] - 119s 2s/step - loss: 0.0329 - accuracy: 0.9900 - val_loss: 2.5637 - val_accuracy: 0.7170
## plotting the graph of validation to test for over fitting
accuracy = history.history["accuracy"]
val_accuracy = history.history["val_accuracy"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]
epochs = range(1, len(accuracy) + 1)
plt.plot(epochs, accuracy, "bo", label="Training accuracy")
plt.plot(epochs, val_accuracy, "b", label="Validation accuracy")
plt.title("Training and validation accuracy")
plt.legend()
plt.figure()
plt.plot(epochs, loss, "bo", label="Training loss")
plt.plot(epochs, val_loss, "b", label="Validation loss")
plt.title("Training and validation loss")
plt.legend()
plt.show()
test_model = keras.models.load_model("./models/convnet_from_scratch.keras")
test_loss, test_acc = test_model.evaluate(test_dataset)
print(f"Test accuracy: {test_acc:.3f}")
63/63 [==============================] - 22s 343ms/step - loss: 0.5936 - accuracy: 0.7300 Test accuracy: 0.730
data_augmentation = keras.Sequential(
[
layers.RandomFlip("horizontal"),
layers.RandomRotation(0.1),
layers.RandomZoom(0.2),
]
)
plt.figure(figsize=(10, 10))
for images, _ in train_dataset.take(1):
for i in range(9):
augmented_images = data_augmentation(images)
ax = plt.subplot(3, 3, i + 1)
plt.imshow(augmented_images[0].numpy().astype("uint8"))
plt.axis("off")
inputs = keras.Input(shape=(180, 180, 3))
x = data_augmentation(inputs)
x = layers.Rescaling(1./255)(x)
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.Flatten()(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
model.compile(loss="binary_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
model.summary()
Model: "model_5"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_9 (InputLayer) [(None, 180, 180, 3)] 0
sequential_3 (Sequential) (None, 180, 180, 3) 0
rescaling_3 (Rescaling) (None, 180, 180, 3) 0
conv2d_15 (Conv2D) (None, 178, 178, 32) 896
max_pooling2d_12 (MaxPoolin (None, 89, 89, 32) 0
g2D)
conv2d_16 (Conv2D) (None, 87, 87, 64) 18496
max_pooling2d_13 (MaxPoolin (None, 43, 43, 64) 0
g2D)
conv2d_17 (Conv2D) (None, 41, 41, 128) 73856
max_pooling2d_14 (MaxPoolin (None, 20, 20, 128) 0
g2D)
conv2d_18 (Conv2D) (None, 18, 18, 256) 295168
max_pooling2d_15 (MaxPoolin (None, 9, 9, 256) 0
g2D)
conv2d_19 (Conv2D) (None, 7, 7, 256) 590080
flatten_7 (Flatten) (None, 12544) 0
dropout_7 (Dropout) (None, 12544) 0
dense_17 (Dense) (None, 1) 12545
=================================================================
Total params: 991,041
Trainable params: 991,041
Non-trainable params: 0
_________________________________________________________________
## Saving bnest model after data augumentation
callbacks = [
keras.callbacks.ModelCheckpoint(
filepath="./models/convnet_from_scratch_with_augmentation.keras",
save_best_only=True,
monitor="val_loss")
]
history = model.fit(
train_dataset,
epochs=100,
validation_data=validation_dataset,
callbacks=callbacks)
Epoch 1/100 63/63 [==============================] - 137s 2s/step - loss: 0.6935 - accuracy: 0.5045 - val_loss: 0.6911 - val_accuracy: 0.5000 Epoch 2/100 63/63 [==============================] - 139s 2s/step - loss: 0.6943 - accuracy: 0.5185 - val_loss: 0.6887 - val_accuracy: 0.5060 Epoch 3/100 63/63 [==============================] - 163s 3s/step - loss: 0.6911 - accuracy: 0.5690 - val_loss: 0.6730 - val_accuracy: 0.6150 Epoch 4/100 63/63 [==============================] - 145s 2s/step - loss: 0.6805 - accuracy: 0.5955 - val_loss: 0.6790 - val_accuracy: 0.5210 Epoch 5/100 63/63 [==============================] - 130s 2s/step - loss: 0.6538 - accuracy: 0.6295 - val_loss: 0.6542 - val_accuracy: 0.5670 Epoch 6/100 63/63 [==============================] - 131s 2s/step - loss: 0.6387 - accuracy: 0.6320 - val_loss: 0.5987 - val_accuracy: 0.7040 Epoch 7/100 63/63 [==============================] - 131s 2s/step - loss: 0.6349 - accuracy: 0.6515 - val_loss: 0.5904 - val_accuracy: 0.6710 Epoch 8/100 63/63 [==============================] - 130s 2s/step - loss: 0.6121 - accuracy: 0.6660 - val_loss: 0.5874 - val_accuracy: 0.6830 Epoch 9/100 63/63 [==============================] - 130s 2s/step - loss: 0.5935 - accuracy: 0.6855 - val_loss: 0.5936 - val_accuracy: 0.6720 Epoch 10/100 63/63 [==============================] - 130s 2s/step - loss: 0.5744 - accuracy: 0.6965 - val_loss: 0.5634 - val_accuracy: 0.7080 Epoch 11/100 63/63 [==============================] - 130s 2s/step - loss: 0.5704 - accuracy: 0.7095 - val_loss: 0.5509 - val_accuracy: 0.7210 Epoch 12/100 63/63 [==============================] - 130s 2s/step - loss: 0.5603 - accuracy: 0.7290 - val_loss: 0.5320 - val_accuracy: 0.7360 Epoch 13/100 63/63 [==============================] - 131s 2s/step - loss: 0.5347 - accuracy: 0.7285 - val_loss: 0.5406 - val_accuracy: 0.7170 Epoch 14/100 63/63 [==============================] - 130s 2s/step - loss: 0.5285 - accuracy: 0.7395 - val_loss: 0.6124 - val_accuracy: 0.6800 Epoch 15/100 63/63 [==============================] - 128s 2s/step - loss: 0.5315 - accuracy: 0.7425 - val_loss: 0.5201 - val_accuracy: 0.7180 Epoch 16/100 63/63 [==============================] - 131s 2s/step - loss: 0.5060 - accuracy: 0.7480 - val_loss: 0.5581 - val_accuracy: 0.7230 Epoch 17/100 63/63 [==============================] - 129s 2s/step - loss: 0.4963 - accuracy: 0.7610 - val_loss: 0.5962 - val_accuracy: 0.6940 Epoch 18/100 63/63 [==============================] - 128s 2s/step - loss: 0.4844 - accuracy: 0.7735 - val_loss: 0.4784 - val_accuracy: 0.7710 Epoch 19/100 63/63 [==============================] - 132s 2s/step - loss: 0.4823 - accuracy: 0.7765 - val_loss: 0.4550 - val_accuracy: 0.7700 Epoch 20/100 63/63 [==============================] - 128s 2s/step - loss: 0.4723 - accuracy: 0.7780 - val_loss: 0.5874 - val_accuracy: 0.6980 Epoch 21/100 63/63 [==============================] - 129s 2s/step - loss: 0.4705 - accuracy: 0.7695 - val_loss: 0.5148 - val_accuracy: 0.7460 Epoch 22/100 63/63 [==============================] - 128s 2s/step - loss: 0.4675 - accuracy: 0.7805 - val_loss: 0.6825 - val_accuracy: 0.6970 Epoch 23/100 63/63 [==============================] - 128s 2s/step - loss: 0.4561 - accuracy: 0.7850 - val_loss: 0.5663 - val_accuracy: 0.7300 Epoch 24/100 63/63 [==============================] - 129s 2s/step - loss: 0.4647 - accuracy: 0.7760 - val_loss: 0.4583 - val_accuracy: 0.7820 Epoch 25/100 63/63 [==============================] - 127s 2s/step - loss: 0.4373 - accuracy: 0.7920 - val_loss: 0.4738 - val_accuracy: 0.7960 Epoch 26/100 63/63 [==============================] - 128s 2s/step - loss: 0.4387 - accuracy: 0.7995 - val_loss: 0.5536 - val_accuracy: 0.7310 Epoch 27/100 63/63 [==============================] - 128s 2s/step - loss: 0.4114 - accuracy: 0.8115 - val_loss: 0.4780 - val_accuracy: 0.7780 Epoch 28/100 63/63 [==============================] - 127s 2s/step - loss: 0.4250 - accuracy: 0.8125 - val_loss: 0.4732 - val_accuracy: 0.7940 Epoch 29/100 63/63 [==============================] - 129s 2s/step - loss: 0.3969 - accuracy: 0.8195 - val_loss: 0.4860 - val_accuracy: 0.7560 Epoch 30/100 63/63 [==============================] - 133s 2s/step - loss: 0.4053 - accuracy: 0.8165 - val_loss: 0.4486 - val_accuracy: 0.8100 Epoch 31/100 63/63 [==============================] - 128s 2s/step - loss: 0.3962 - accuracy: 0.8200 - val_loss: 0.4245 - val_accuracy: 0.8190 Epoch 32/100 63/63 [==============================] - 132s 2s/step - loss: 0.3829 - accuracy: 0.8275 - val_loss: 0.5573 - val_accuracy: 0.7850 Epoch 33/100 63/63 [==============================] - 128s 2s/step - loss: 0.3966 - accuracy: 0.8305 - val_loss: 0.4460 - val_accuracy: 0.8260 Epoch 34/100 63/63 [==============================] - 127s 2s/step - loss: 0.3661 - accuracy: 0.8345 - val_loss: 0.4010 - val_accuracy: 0.8370 Epoch 35/100 63/63 [==============================] - 126s 2s/step - loss: 0.3697 - accuracy: 0.8390 - val_loss: 0.4826 - val_accuracy: 0.8230 Epoch 36/100 63/63 [==============================] - 127s 2s/step - loss: 0.3699 - accuracy: 0.8365 - val_loss: 0.4994 - val_accuracy: 0.8050 Epoch 37/100 63/63 [==============================] - 125s 2s/step - loss: 0.3442 - accuracy: 0.8520 - val_loss: 0.4589 - val_accuracy: 0.8230 Epoch 38/100 63/63 [==============================] - 127s 2s/step - loss: 0.3431 - accuracy: 0.8465 - val_loss: 0.4029 - val_accuracy: 0.8500 Epoch 39/100 63/63 [==============================] - 128s 2s/step - loss: 0.3389 - accuracy: 0.8545 - val_loss: 0.3722 - val_accuracy: 0.8470 Epoch 40/100 63/63 [==============================] - 128s 2s/step - loss: 0.3363 - accuracy: 0.8545 - val_loss: 0.3817 - val_accuracy: 0.8370 Epoch 41/100 63/63 [==============================] - 127s 2s/step - loss: 0.3232 - accuracy: 0.8520 - val_loss: 0.5308 - val_accuracy: 0.7770 Epoch 42/100 63/63 [==============================] - 129s 2s/step - loss: 0.3098 - accuracy: 0.8640 - val_loss: 0.3744 - val_accuracy: 0.8470 Epoch 43/100 63/63 [==============================] - 129s 2s/step - loss: 0.3121 - accuracy: 0.8650 - val_loss: 0.3857 - val_accuracy: 0.8320 Epoch 44/100 63/63 [==============================] - 128s 2s/step - loss: 0.3055 - accuracy: 0.8710 - val_loss: 0.5000 - val_accuracy: 0.8280 Epoch 45/100 63/63 [==============================] - 127s 2s/step - loss: 0.2961 - accuracy: 0.8805 - val_loss: 0.4055 - val_accuracy: 0.8390 Epoch 46/100 63/63 [==============================] - 128s 2s/step - loss: 0.2994 - accuracy: 0.8705 - val_loss: 0.6383 - val_accuracy: 0.7660 Epoch 47/100 63/63 [==============================] - 128s 2s/step - loss: 0.2808 - accuracy: 0.8965 - val_loss: 0.9280 - val_accuracy: 0.7680 Epoch 48/100 63/63 [==============================] - 126s 2s/step - loss: 0.3125 - accuracy: 0.8770 - val_loss: 0.3867 - val_accuracy: 0.8500 Epoch 49/100 63/63 [==============================] - 128s 2s/step - loss: 0.3028 - accuracy: 0.8845 - val_loss: 0.3980 - val_accuracy: 0.8440 Epoch 50/100 63/63 [==============================] - 129s 2s/step - loss: 0.2690 - accuracy: 0.8845 - val_loss: 0.4223 - val_accuracy: 0.8290 Epoch 51/100 63/63 [==============================] - 127s 2s/step - loss: 0.2825 - accuracy: 0.8775 - val_loss: 0.5000 - val_accuracy: 0.8130 Epoch 52/100 63/63 [==============================] - 127s 2s/step - loss: 0.2718 - accuracy: 0.8840 - val_loss: 0.5160 - val_accuracy: 0.8070 Epoch 53/100 63/63 [==============================] - 127s 2s/step - loss: 0.2579 - accuracy: 0.9005 - val_loss: 0.4458 - val_accuracy: 0.8360 Epoch 54/100 63/63 [==============================] - 127s 2s/step - loss: 0.2325 - accuracy: 0.9040 - val_loss: 0.5505 - val_accuracy: 0.8360 Epoch 55/100 63/63 [==============================] - 127s 2s/step - loss: 0.2319 - accuracy: 0.9010 - val_loss: 0.5860 - val_accuracy: 0.8310 Epoch 56/100 63/63 [==============================] - 129s 2s/step - loss: 0.2726 - accuracy: 0.8940 - val_loss: 0.3929 - val_accuracy: 0.8480 Epoch 57/100 63/63 [==============================] - 127s 2s/step - loss: 0.2571 - accuracy: 0.8995 - val_loss: 0.4040 - val_accuracy: 0.8620 Epoch 58/100 63/63 [==============================] - 130s 2s/step - loss: 0.2302 - accuracy: 0.9050 - val_loss: 0.5461 - val_accuracy: 0.8420 Epoch 59/100 63/63 [==============================] - 128s 2s/step - loss: 0.2339 - accuracy: 0.9095 - val_loss: 0.4613 - val_accuracy: 0.8310 Epoch 60/100 63/63 [==============================] - 130s 2s/step - loss: 0.2343 - accuracy: 0.9020 - val_loss: 0.5716 - val_accuracy: 0.7990 Epoch 61/100 63/63 [==============================] - 127s 2s/step - loss: 0.2193 - accuracy: 0.9180 - val_loss: 0.5431 - val_accuracy: 0.8400 Epoch 62/100 63/63 [==============================] - 129s 2s/step - loss: 0.2406 - accuracy: 0.9095 - val_loss: 0.5672 - val_accuracy: 0.8250 Epoch 63/100 63/63 [==============================] - 128s 2s/step - loss: 0.2195 - accuracy: 0.9150 - val_loss: 0.4641 - val_accuracy: 0.8400 Epoch 64/100 63/63 [==============================] - 128s 2s/step - loss: 0.2171 - accuracy: 0.9090 - val_loss: 0.3938 - val_accuracy: 0.8560 Epoch 65/100 63/63 [==============================] - 128s 2s/step - loss: 0.2036 - accuracy: 0.9200 - val_loss: 0.4000 - val_accuracy: 0.8620 Epoch 66/100 63/63 [==============================] - 128s 2s/step - loss: 0.1931 - accuracy: 0.9235 - val_loss: 0.5545 - val_accuracy: 0.8490 Epoch 67/100 63/63 [==============================] - 127s 2s/step - loss: 0.1941 - accuracy: 0.9220 - val_loss: 0.5454 - val_accuracy: 0.8250 Epoch 68/100 63/63 [==============================] - 127s 2s/step - loss: 0.1995 - accuracy: 0.9200 - val_loss: 0.4163 - val_accuracy: 0.8560 Epoch 69/100 63/63 [==============================] - 127s 2s/step - loss: 0.1960 - accuracy: 0.9240 - val_loss: 0.8856 - val_accuracy: 0.8070 Epoch 70/100 63/63 [==============================] - 129s 2s/step - loss: 0.2114 - accuracy: 0.9180 - val_loss: 0.4526 - val_accuracy: 0.8360 Epoch 71/100 63/63 [==============================] - 128s 2s/step - loss: 0.1848 - accuracy: 0.9220 - val_loss: 0.9678 - val_accuracy: 0.7860 Epoch 72/100 63/63 [==============================] - 129s 2s/step - loss: 0.1964 - accuracy: 0.9245 - val_loss: 0.4552 - val_accuracy: 0.8730 Epoch 73/100 63/63 [==============================] - 128s 2s/step - loss: 0.1778 - accuracy: 0.9310 - val_loss: 0.5401 - val_accuracy: 0.8520 Epoch 74/100 63/63 [==============================] - 126s 2s/step - loss: 0.1852 - accuracy: 0.9305 - val_loss: 0.6431 - val_accuracy: 0.8380 Epoch 75/100 63/63 [==============================] - 128s 2s/step - loss: 0.1737 - accuracy: 0.9295 - val_loss: 0.4932 - val_accuracy: 0.8530 Epoch 76/100 63/63 [==============================] - 128s 2s/step - loss: 0.1919 - accuracy: 0.9300 - val_loss: 0.6262 - val_accuracy: 0.8190 Epoch 77/100 63/63 [==============================] - 127s 2s/step - loss: 0.1594 - accuracy: 0.9375 - val_loss: 0.6038 - val_accuracy: 0.8630 Epoch 78/100 63/63 [==============================] - 127s 2s/step - loss: 0.1825 - accuracy: 0.9295 - val_loss: 0.4211 - val_accuracy: 0.8720 Epoch 79/100 63/63 [==============================] - 129s 2s/step - loss: 0.1623 - accuracy: 0.9440 - val_loss: 0.6230 - val_accuracy: 0.8470 Epoch 80/100 63/63 [==============================] - 127s 2s/step - loss: 0.1736 - accuracy: 0.9345 - val_loss: 0.6382 - val_accuracy: 0.8580 Epoch 81/100 63/63 [==============================] - 127s 2s/step - loss: 0.1948 - accuracy: 0.9340 - val_loss: 0.5290 - val_accuracy: 0.8510 Epoch 82/100 63/63 [==============================] - 128s 2s/step - loss: 0.1936 - accuracy: 0.9340 - val_loss: 0.4778 - val_accuracy: 0.8650 Epoch 83/100 63/63 [==============================] - 128s 2s/step - loss: 0.1617 - accuracy: 0.9415 - val_loss: 0.6838 - val_accuracy: 0.8610 Epoch 84/100 63/63 [==============================] - 127s 2s/step - loss: 0.1763 - accuracy: 0.9370 - val_loss: 0.7011 - val_accuracy: 0.8250 Epoch 85/100 63/63 [==============================] - 128s 2s/step - loss: 0.1733 - accuracy: 0.9350 - val_loss: 0.6602 - val_accuracy: 0.8410 Epoch 86/100 63/63 [==============================] - 129s 2s/step - loss: 0.1487 - accuracy: 0.9405 - val_loss: 0.8419 - val_accuracy: 0.8390 Epoch 87/100 63/63 [==============================] - 128s 2s/step - loss: 0.1867 - accuracy: 0.9330 - val_loss: 0.5493 - val_accuracy: 0.8490 Epoch 88/100 63/63 [==============================] - 128s 2s/step - loss: 0.1667 - accuracy: 0.9370 - val_loss: 0.5301 - val_accuracy: 0.8750 Epoch 89/100 63/63 [==============================] - 128s 2s/step - loss: 0.2002 - accuracy: 0.9365 - val_loss: 0.5077 - val_accuracy: 0.8730 Epoch 90/100 63/63 [==============================] - 127s 2s/step - loss: 0.1870 - accuracy: 0.9350 - val_loss: 1.1831 - val_accuracy: 0.7410 Epoch 91/100 63/63 [==============================] - 127s 2s/step - loss: 0.1846 - accuracy: 0.9410 - val_loss: 0.6067 - val_accuracy: 0.8630 Epoch 92/100 63/63 [==============================] - 128s 2s/step - loss: 0.1403 - accuracy: 0.9485 - val_loss: 0.4924 - val_accuracy: 0.8840 Epoch 93/100 63/63 [==============================] - 127s 2s/step - loss: 0.1622 - accuracy: 0.9400 - val_loss: 0.6148 - val_accuracy: 0.8310 Epoch 94/100 63/63 [==============================] - 128s 2s/step - loss: 0.1617 - accuracy: 0.9400 - val_loss: 0.5684 - val_accuracy: 0.8700 Epoch 95/100 63/63 [==============================] - 129s 2s/step - loss: 0.1494 - accuracy: 0.9485 - val_loss: 0.4870 - val_accuracy: 0.8770 Epoch 96/100 63/63 [==============================] - 128s 2s/step - loss: 0.1645 - accuracy: 0.9375 - val_loss: 0.5286 - val_accuracy: 0.8780 Epoch 97/100 63/63 [==============================] - 127s 2s/step - loss: 0.1691 - accuracy: 0.9425 - val_loss: 0.5684 - val_accuracy: 0.8540 Epoch 98/100 63/63 [==============================] - 128s 2s/step - loss: 0.1662 - accuracy: 0.9435 - val_loss: 0.6468 - val_accuracy: 0.8510 Epoch 99/100 63/63 [==============================] - 129s 2s/step - loss: 0.1451 - accuracy: 0.9550 - val_loss: 0.5671 - val_accuracy: 0.8610 Epoch 100/100 63/63 [==============================] - 127s 2s/step - loss: 0.1727 - accuracy: 0.9390 - val_loss: 0.6904 - val_accuracy: 0.8560
test_model = keras.models.load_model(
"./models/convnet_from_scratch_with_augmentation.keras")
test_loss, test_acc = test_model.evaluate(test_dataset)
print(f"Test accuracy: {test_acc:.3f}")
63/63 [==============================] - 23s 345ms/step - loss: 0.4094 - accuracy: 0.8185 Test accuracy: 0.818
## plotting the validation graph to test for overfitting
accuracy = history.history["accuracy"]
val_accuracy = history.history["val_accuracy"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]
epochs = range(1, len(accuracy) + 1)
plt.plot(epochs, accuracy, "bo", label="Training accuracy")
plt.plot(epochs, val_accuracy, "b", label="Validation accuracy")
plt.title("Training and validation accuracy")
plt.legend()
plt.figure()
plt.plot(epochs, loss, "bo", label="Training loss")
plt.plot(epochs, val_loss, "b", label="Validation loss")
plt.title("Training and validation loss")
plt.legend()
plt.show()
# Load the VGG16 base model
conv_base = keras.applications.vgg16.VGG16(weights='imagenet', include_top=False, input_shape=(180, 180, 3))
conv_base.summary()
Model: "vgg16"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_6 (InputLayer) [(None, 180, 180, 3)] 0
block1_conv1 (Conv2D) (None, 180, 180, 64) 1792
block1_conv2 (Conv2D) (None, 180, 180, 64) 36928
block1_pool (MaxPooling2D) (None, 90, 90, 64) 0
block2_conv1 (Conv2D) (None, 90, 90, 128) 73856
block2_conv2 (Conv2D) (None, 90, 90, 128) 147584
block2_pool (MaxPooling2D) (None, 45, 45, 128) 0
block3_conv1 (Conv2D) (None, 45, 45, 256) 295168
block3_conv2 (Conv2D) (None, 45, 45, 256) 590080
block3_conv3 (Conv2D) (None, 45, 45, 256) 590080
block3_pool (MaxPooling2D) (None, 22, 22, 256) 0
block4_conv1 (Conv2D) (None, 22, 22, 512) 1180160
block4_conv2 (Conv2D) (None, 22, 22, 512) 2359808
block4_conv3 (Conv2D) (None, 22, 22, 512) 2359808
block4_pool (MaxPooling2D) (None, 11, 11, 512) 0
block5_conv1 (Conv2D) (None, 11, 11, 512) 2359808
block5_conv2 (Conv2D) (None, 11, 11, 512) 2359808
block5_conv3 (Conv2D) (None, 11, 11, 512) 2359808
block5_pool (MaxPooling2D) (None, 5, 5, 512) 0
=================================================================
Total params: 14,714,688
Trainable params: 14,714,688
Non-trainable params: 0
_________________________________________________________________
# This should point to the small dataset of the Kaggle Dogs vs Cats competition that was created in a previous notebook
data_folder = pathlib.Path('../data/kaggle_dogs_vs_cats_small')
train_dataset = image_dataset_from_directory(
data_folder / "train",
image_size=(180, 180),
batch_size=32)
validation_dataset = image_dataset_from_directory(
data_folder / "validation",
image_size=(180, 180),
batch_size=32)
test_dataset = image_dataset_from_directory(
data_folder / "test",
image_size=(180, 180),
batch_size=32)
Found 2000 files belonging to 2 classes. Found 1000 files belonging to 2 classes. Found 2000 files belonging to 2 classes.
import numpy as np
def get_features_and_labels(dataset):
all_features = []
all_labels = []
for images, labels in dataset:
preprocessed_images = keras.applications.vgg16.preprocess_input(images)
features = conv_base.predict(preprocessed_images)
all_features.append(features)
all_labels.append(labels)
return np.concatenate(all_features), np.concatenate(all_labels)
train_features, train_labels = get_features_and_labels(train_dataset)
val_features, val_labels = get_features_and_labels(validation_dataset)
test_features, test_labels = get_features_and_labels(test_dataset)
1/1 [==============================] - 5s 5s/step 1/1 [==============================] - 4s 4s/step 1/1 [==============================] - 5s 5s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 9s 9s/step 1/1 [==============================] - 10s 10s/step 1/1 [==============================] - 9s 9s/step 1/1 [==============================] - 11s 11s/step 1/1 [==============================] - 9s 9s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 8s 8s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 4s 4s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 2s 2s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 8s 8s/step 1/1 [==============================] - 8s 8s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 8s 8s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 9s 9s/step 1/1 [==============================] - 8s 8s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 9s 9s/step 1/1 [==============================] - 9s 9s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 6s 6s/step 1/1 [==============================] - 7s 7s/step 1/1 [==============================] - 3s 3s/step
train_features.shape
(2000, 5, 5, 512)
inputs = keras.Input(shape=(5, 5, 512))
x = layers.Flatten()(inputs)
x = layers.Dense(256)(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model_2 = keras.Model(inputs, outputs)
model_2.summary()
Model: "model_4"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_8 (InputLayer) [(None, 5, 5, 512)] 0
flatten_6 (Flatten) (None, 12800) 0
dense_15 (Dense) (None, 256) 3277056
dropout_6 (Dropout) (None, 256) 0
dense_16 (Dense) (None, 1) 257
=================================================================
Total params: 3,277,313
Trainable params: 3,277,313
Non-trainable params: 0
_________________________________________________________________
model_2.compile(loss="binary_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
## saving the best vgg model after feature extraction
callbacks = [
keras.callbacks.ModelCheckpoint(
filepath="./models/feature_extraction.keras",
save_best_only=True,
monitor="val_loss")
]
history = model_2.fit(
train_features, train_labels,
epochs=20,
validation_data=(val_features, val_labels),
callbacks=callbacks)
Epoch 1/20 63/63 [==============================] - 3s 42ms/step - loss: 18.7081 - accuracy: 0.9250 - val_loss: 8.9500 - val_accuracy: 0.9530 Epoch 2/20 63/63 [==============================] - 3s 47ms/step - loss: 4.1287 - accuracy: 0.9750 - val_loss: 5.3200 - val_accuracy: 0.9710 Epoch 3/20 63/63 [==============================] - 3s 44ms/step - loss: 2.9608 - accuracy: 0.9800 - val_loss: 5.0919 - val_accuracy: 0.9760 Epoch 4/20 63/63 [==============================] - 3s 45ms/step - loss: 1.0977 - accuracy: 0.9915 - val_loss: 6.7650 - val_accuracy: 0.9720 Epoch 5/20 63/63 [==============================] - 3s 44ms/step - loss: 0.4824 - accuracy: 0.9965 - val_loss: 3.8781 - val_accuracy: 0.9780 Epoch 6/20 63/63 [==============================] - 3s 51ms/step - loss: 0.6690 - accuracy: 0.9935 - val_loss: 5.3692 - val_accuracy: 0.9720 Epoch 7/20 63/63 [==============================] - 3s 42ms/step - loss: 0.1919 - accuracy: 0.9980 - val_loss: 5.7011 - val_accuracy: 0.9680 Epoch 8/20 63/63 [==============================] - 3s 47ms/step - loss: 0.2520 - accuracy: 0.9970 - val_loss: 7.7003 - val_accuracy: 0.9700 Epoch 9/20 63/63 [==============================] - 3s 41ms/step - loss: 0.2487 - accuracy: 0.9965 - val_loss: 5.0559 - val_accuracy: 0.9760 Epoch 10/20 63/63 [==============================] - 3s 44ms/step - loss: 0.4490 - accuracy: 0.9965 - val_loss: 5.9799 - val_accuracy: 0.9710 Epoch 11/20 63/63 [==============================] - 3s 41ms/step - loss: 0.3175 - accuracy: 0.9980 - val_loss: 6.7661 - val_accuracy: 0.9720 Epoch 12/20 63/63 [==============================] - 3s 45ms/step - loss: 0.3138 - accuracy: 0.9975 - val_loss: 4.9448 - val_accuracy: 0.9760 Epoch 13/20 63/63 [==============================] - 2s 38ms/step - loss: 0.1435 - accuracy: 0.9970 - val_loss: 8.1980 - val_accuracy: 0.9660 Epoch 14/20 63/63 [==============================] - 2s 34ms/step - loss: 0.3526 - accuracy: 0.9975 - val_loss: 5.3656 - val_accuracy: 0.9790 Epoch 15/20 63/63 [==============================] - 2s 35ms/step - loss: 0.3480 - accuracy: 0.9960 - val_loss: 5.7172 - val_accuracy: 0.9750 Epoch 16/20 63/63 [==============================] - 2s 33ms/step - loss: 0.0585 - accuracy: 0.9975 - val_loss: 8.0958 - val_accuracy: 0.9740 Epoch 17/20 63/63 [==============================] - 2s 36ms/step - loss: 0.0711 - accuracy: 0.9995 - val_loss: 5.9155 - val_accuracy: 0.9730 Epoch 18/20 63/63 [==============================] - 4s 61ms/step - loss: 0.2832 - accuracy: 0.9970 - val_loss: 4.6287 - val_accuracy: 0.9800 Epoch 19/20 63/63 [==============================] - 3s 43ms/step - loss: 0.0217 - accuracy: 0.9990 - val_loss: 4.4280 - val_accuracy: 0.9810 Epoch 20/20 63/63 [==============================] - 3s 47ms/step - loss: 0.1145 - accuracy: 0.9985 - val_loss: 5.4172 - val_accuracy: 0.9790
## plotting validation to test for overfitting
import matplotlib.pyplot as plt
acc = history.history["accuracy"]
val_acc = history.history["val_accuracy"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]
epochs = range(1, len(acc) + 1)
plt.plot(epochs, acc, "bo", label="Training accuracy")
plt.plot(epochs, val_acc, "b", label="Validation accuracy")
plt.title("Training and validation accuracy")
plt.legend()
plt.figure()
plt.plot(epochs, loss, "bo", label="Training loss")
plt.plot(epochs, val_loss, "b", label="Validation loss")
plt.title("Training and validation loss")
plt.legend()
plt.show()
test_model_2 = keras.models.load_model(
"./models/feature_extraction.keras")
test_loss, test_acc = test_model_2.evaluate(x=test_features, y=test_labels)
print(f"Test accuracy: {test_acc:.3f}")
63/63 [==============================] - 1s 6ms/step - loss: 4.9087 - accuracy: 0.9720 Test accuracy: 0.972
conv_base = keras.applications.vgg16.VGG16(
weights="imagenet",
include_top=False)
conv_base.summary()
Model: "vgg16"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_10 (InputLayer) [(None, None, None, 3)] 0
block1_conv1 (Conv2D) (None, None, None, 64) 1792
block1_conv2 (Conv2D) (None, None, None, 64) 36928
block1_pool (MaxPooling2D) (None, None, None, 64) 0
block2_conv1 (Conv2D) (None, None, None, 128) 73856
block2_conv2 (Conv2D) (None, None, None, 128) 147584
block2_pool (MaxPooling2D) (None, None, None, 128) 0
block3_conv1 (Conv2D) (None, None, None, 256) 295168
block3_conv2 (Conv2D) (None, None, None, 256) 590080
block3_conv3 (Conv2D) (None, None, None, 256) 590080
block3_pool (MaxPooling2D) (None, None, None, 256) 0
block4_conv1 (Conv2D) (None, None, None, 512) 1180160
block4_conv2 (Conv2D) (None, None, None, 512) 2359808
block4_conv3 (Conv2D) (None, None, None, 512) 2359808
block4_pool (MaxPooling2D) (None, None, None, 512) 0
block5_conv1 (Conv2D) (None, None, None, 512) 2359808
block5_conv2 (Conv2D) (None, None, None, 512) 2359808
block5_conv3 (Conv2D) (None, None, None, 512) 2359808
block5_pool (MaxPooling2D) (None, None, None, 512) 0
=================================================================
Total params: 14,714,688
Trainable params: 14,714,688
Non-trainable params: 0
_________________________________________________________________
conv_base.trainable = False
conv_base.summary()
Model: "vgg16"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_10 (InputLayer) [(None, None, None, 3)] 0
block1_conv1 (Conv2D) (None, None, None, 64) 1792
block1_conv2 (Conv2D) (None, None, None, 64) 36928
block1_pool (MaxPooling2D) (None, None, None, 64) 0
block2_conv1 (Conv2D) (None, None, None, 128) 73856
block2_conv2 (Conv2D) (None, None, None, 128) 147584
block2_pool (MaxPooling2D) (None, None, None, 128) 0
block3_conv1 (Conv2D) (None, None, None, 256) 295168
block3_conv2 (Conv2D) (None, None, None, 256) 590080
block3_conv3 (Conv2D) (None, None, None, 256) 590080
block3_pool (MaxPooling2D) (None, None, None, 256) 0
block4_conv1 (Conv2D) (None, None, None, 512) 1180160
block4_conv2 (Conv2D) (None, None, None, 512) 2359808
block4_conv3 (Conv2D) (None, None, None, 512) 2359808
block4_pool (MaxPooling2D) (None, None, None, 512) 0
block5_conv1 (Conv2D) (None, None, None, 512) 2359808
block5_conv2 (Conv2D) (None, None, None, 512) 2359808
block5_conv3 (Conv2D) (None, None, None, 512) 2359808
block5_pool (MaxPooling2D) (None, None, None, 512) 0
=================================================================
Total params: 14,714,688
Trainable params: 0
Non-trainable params: 14,714,688
_________________________________________________________________
data_augmentation = keras.Sequential(
[
layers.RandomFlip("horizontal"),
layers.RandomRotation(0.1),
layers.RandomZoom(0.2),
]
)
inputs = keras.Input(shape=(180, 180, 3))
x = data_augmentation(inputs)
x = keras.applications.vgg16.preprocess_input(x)
x = conv_base(x)
x = layers.Flatten()(x)
x = layers.Dense(256)(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model_2 = keras.Model(inputs, outputs)
model_2.summary()
Model: "model_11"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_16 (InputLayer) [(None, 180, 180, 3)] 0
sequential_9 (Sequential) (None, 180, 180, 3) 0
tf.__operators__.getitem_5 (None, 180, 180, 3) 0
(SlicingOpLambda)
tf.nn.bias_add_5 (TFOpLambd (None, 180, 180, 3) 0
a)
vgg16 (Functional) (None, None, None, 512) 14714688
flatten_13 (Flatten) (None, 12800) 0
dense_28 (Dense) (None, 256) 3277056
dropout_13 (Dropout) (None, 256) 0
dense_29 (Dense) (None, 1) 257
=================================================================
Total params: 17,992,001
Trainable params: 3,277,313
Non-trainable params: 14,714,688
_________________________________________________________________
model_2.compile(loss="binary_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
## saving the best vgg16 model after data augumentation.
callbacks = [
keras.callbacks.ModelCheckpoint(
filepath="./models/feature_extraction_with_data_augmentation.keras",
save_best_only=True,
monitor="val_loss")
]
history = model_2.fit(
train_dataset,
epochs=50,
validation_data=validation_dataset,
callbacks=callbacks)
Epoch 1/50 63/63 [==============================] - 592s 9s/step - loss: 20.6140 - accuracy: 0.8900 - val_loss: 4.0610 - val_accuracy: 0.9670 Epoch 2/50 63/63 [==============================] - 597s 9s/step - loss: 7.0461 - accuracy: 0.9445 - val_loss: 4.5346 - val_accuracy: 0.9640 Epoch 3/50 63/63 [==============================] - 602s 10s/step - loss: 5.1694 - accuracy: 0.9550 - val_loss: 5.2695 - val_accuracy: 0.9680 Epoch 4/50 63/63 [==============================] - 603s 10s/step - loss: 6.4113 - accuracy: 0.9550 - val_loss: 5.5086 - val_accuracy: 0.9680 Epoch 5/50 63/63 [==============================] - 596s 9s/step - loss: 3.7493 - accuracy: 0.9650 - val_loss: 3.3889 - val_accuracy: 0.9770 Epoch 6/50 63/63 [==============================] - 596s 10s/step - loss: 3.3527 - accuracy: 0.9705 - val_loss: 5.0493 - val_accuracy: 0.9720 Epoch 7/50 63/63 [==============================] - 601s 10s/step - loss: 3.4541 - accuracy: 0.9625 - val_loss: 3.1545 - val_accuracy: 0.9790 Epoch 8/50 63/63 [==============================] - 598s 10s/step - loss: 3.6030 - accuracy: 0.9675 - val_loss: 5.1328 - val_accuracy: 0.9740 Epoch 9/50 63/63 [==============================] - 598s 10s/step - loss: 2.1408 - accuracy: 0.9780 - val_loss: 6.4363 - val_accuracy: 0.9640 Epoch 10/50 63/63 [==============================] - 597s 10s/step - loss: 2.7302 - accuracy: 0.9730 - val_loss: 3.0570 - val_accuracy: 0.9740 Epoch 11/50 63/63 [==============================] - 599s 10s/step - loss: 2.2155 - accuracy: 0.9750 - val_loss: 2.7919 - val_accuracy: 0.9750 Epoch 12/50 63/63 [==============================] - 597s 10s/step - loss: 1.8460 - accuracy: 0.9740 - val_loss: 7.4428 - val_accuracy: 0.9590 Epoch 13/50 63/63 [==============================] - 601s 10s/step - loss: 1.4545 - accuracy: 0.9795 - val_loss: 4.9208 - val_accuracy: 0.9710 Epoch 14/50 63/63 [==============================] - 597s 10s/step - loss: 1.4135 - accuracy: 0.9790 - val_loss: 3.0567 - val_accuracy: 0.9720 Epoch 15/50 63/63 [==============================] - 603s 10s/step - loss: 1.2776 - accuracy: 0.9805 - val_loss: 2.2792 - val_accuracy: 0.9780 Epoch 16/50 63/63 [==============================] - 597s 10s/step - loss: 1.4346 - accuracy: 0.9830 - val_loss: 2.5536 - val_accuracy: 0.9770 Epoch 17/50 63/63 [==============================] - 598s 10s/step - loss: 1.5318 - accuracy: 0.9820 - val_loss: 2.2488 - val_accuracy: 0.9750 Epoch 18/50 63/63 [==============================] - 599s 10s/step - loss: 1.3871 - accuracy: 0.9820 - val_loss: 3.1731 - val_accuracy: 0.9770 Epoch 19/50 63/63 [==============================] - 603s 10s/step - loss: 1.3470 - accuracy: 0.9810 - val_loss: 2.3953 - val_accuracy: 0.9780 Epoch 20/50 63/63 [==============================] - 597s 10s/step - loss: 1.7832 - accuracy: 0.9745 - val_loss: 3.6023 - val_accuracy: 0.9750 Epoch 21/50 63/63 [==============================] - 598s 10s/step - loss: 0.8156 - accuracy: 0.9845 - val_loss: 3.3980 - val_accuracy: 0.9700 Epoch 22/50 63/63 [==============================] - 602s 10s/step - loss: 1.4364 - accuracy: 0.9800 - val_loss: 2.0980 - val_accuracy: 0.9820 Epoch 23/50 63/63 [==============================] - 602s 10s/step - loss: 1.2875 - accuracy: 0.9765 - val_loss: 3.1463 - val_accuracy: 0.9750 Epoch 24/50 63/63 [==============================] - 597s 10s/step - loss: 0.9568 - accuracy: 0.9855 - val_loss: 3.5346 - val_accuracy: 0.9710 Epoch 25/50 63/63 [==============================] - 599s 10s/step - loss: 0.8887 - accuracy: 0.9870 - val_loss: 2.2362 - val_accuracy: 0.9770 Epoch 26/50 63/63 [==============================] - 598s 10s/step - loss: 0.9552 - accuracy: 0.9830 - val_loss: 1.3277 - val_accuracy: 0.9760 Epoch 27/50 63/63 [==============================] - 599s 10s/step - loss: 0.9044 - accuracy: 0.9820 - val_loss: 1.5658 - val_accuracy: 0.9750 Epoch 28/50 63/63 [==============================] - 601s 10s/step - loss: 0.5588 - accuracy: 0.9905 - val_loss: 1.9886 - val_accuracy: 0.9750 Epoch 29/50 63/63 [==============================] - 597s 10s/step - loss: 1.1501 - accuracy: 0.9810 - val_loss: 1.5269 - val_accuracy: 0.9760 Epoch 30/50 63/63 [==============================] - 596s 10s/step - loss: 0.9899 - accuracy: 0.9820 - val_loss: 2.0775 - val_accuracy: 0.9780 Epoch 31/50 63/63 [==============================] - 600s 10s/step - loss: 0.8323 - accuracy: 0.9865 - val_loss: 1.6117 - val_accuracy: 0.9790 Epoch 32/50 63/63 [==============================] - 598s 10s/step - loss: 0.8424 - accuracy: 0.9860 - val_loss: 2.3115 - val_accuracy: 0.9760 Epoch 33/50 63/63 [==============================] - 598s 10s/step - loss: 1.1347 - accuracy: 0.9800 - val_loss: 2.8145 - val_accuracy: 0.9680 Epoch 34/50 63/63 [==============================] - 598s 10s/step - loss: 0.9453 - accuracy: 0.9860 - val_loss: 1.3357 - val_accuracy: 0.9800 Epoch 35/50 63/63 [==============================] - 595s 9s/step - loss: 0.7595 - accuracy: 0.9865 - val_loss: 1.6864 - val_accuracy: 0.9780 Epoch 36/50 63/63 [==============================] - 598s 10s/step - loss: 0.5730 - accuracy: 0.9880 - val_loss: 2.0145 - val_accuracy: 0.9730 Epoch 37/50 63/63 [==============================] - 602s 10s/step - loss: 0.7360 - accuracy: 0.9870 - val_loss: 1.5725 - val_accuracy: 0.9810 Epoch 38/50 63/63 [==============================] - 599s 10s/step - loss: 0.4907 - accuracy: 0.9865 - val_loss: 1.5609 - val_accuracy: 0.9800 Epoch 39/50 63/63 [==============================] - 597s 10s/step - loss: 0.3515 - accuracy: 0.9895 - val_loss: 1.5007 - val_accuracy: 0.9840 Epoch 40/50 63/63 [==============================] - 600s 10s/step - loss: 0.5639 - accuracy: 0.9820 - val_loss: 1.7320 - val_accuracy: 0.9810 Epoch 41/50 63/63 [==============================] - 601s 10s/step - loss: 0.2159 - accuracy: 0.9920 - val_loss: 1.7512 - val_accuracy: 0.9780 Epoch 42/50 63/63 [==============================] - 600s 10s/step - loss: 0.6466 - accuracy: 0.9875 - val_loss: 2.1830 - val_accuracy: 0.9770 Epoch 43/50 63/63 [==============================] - 601s 10s/step - loss: 0.4846 - accuracy: 0.9890 - val_loss: 2.4422 - val_accuracy: 0.9750 Epoch 44/50 63/63 [==============================] - 605s 10s/step - loss: 0.5897 - accuracy: 0.9865 - val_loss: 2.3110 - val_accuracy: 0.9770 Epoch 45/50 63/63 [==============================] - 592s 9s/step - loss: 0.2892 - accuracy: 0.9920 - val_loss: 1.9352 - val_accuracy: 0.9810 Epoch 46/50 63/63 [==============================] - 592s 9s/step - loss: 0.6942 - accuracy: 0.9880 - val_loss: 2.3598 - val_accuracy: 0.9730 Epoch 47/50 63/63 [==============================] - 591s 9s/step - loss: 0.4928 - accuracy: 0.9880 - val_loss: 2.0690 - val_accuracy: 0.9760 Epoch 48/50 63/63 [==============================] - 594s 9s/step - loss: 0.4423 - accuracy: 0.9850 - val_loss: 1.8178 - val_accuracy: 0.9790 Epoch 49/50 63/63 [==============================] - 591s 9s/step - loss: 0.3455 - accuracy: 0.9895 - val_loss: 1.6294 - val_accuracy: 0.9840 Epoch 50/50 63/63 [==============================] - 592s 9s/step - loss: 0.3852 - accuracy: 0.9915 - val_loss: 1.7606 - val_accuracy: 0.9850
## plotting validation to test for overfitting
acc = history.history["accuracy"]
val_acc = history.history["val_accuracy"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]
epochs = range(1, len(acc) + 1)
plt.plot(epochs, acc, "bo", label="Training accuracy")
plt.plot(epochs, val_acc, "b", label="Validation accuracy")
plt.title("Training and validation accuracy")
plt.legend()
plt.figure()
plt.plot(epochs, loss, "bo", label="Training loss")
plt.plot(epochs, val_loss, "b", label="Validation loss")
plt.title("Training and validation loss")
plt.legend()
plt.show()
test_model_2 = keras.models.load_model(
"./models/feature_extraction_with_data_augmentation.keras")
test_loss, test_acc = test_model_2.evaluate(test_dataset)
print(f"Test accuracy: {test_acc:.3f}")
63/63 [==============================] - 401s 6s/step - loss: 2.2913 - accuracy: 0.9735 Test accuracy: 0.974
### fine tuning the model
conv_base.summary()
Model: "vgg16"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_10 (InputLayer) [(None, None, None, 3)] 0
block1_conv1 (Conv2D) (None, None, None, 64) 1792
block1_conv2 (Conv2D) (None, None, None, 64) 36928
block1_pool (MaxPooling2D) (None, None, None, 64) 0
block2_conv1 (Conv2D) (None, None, None, 128) 73856
block2_conv2 (Conv2D) (None, None, None, 128) 147584
block2_pool (MaxPooling2D) (None, None, None, 128) 0
block3_conv1 (Conv2D) (None, None, None, 256) 295168
block3_conv2 (Conv2D) (None, None, None, 256) 590080
block3_conv3 (Conv2D) (None, None, None, 256) 590080
block3_pool (MaxPooling2D) (None, None, None, 256) 0
block4_conv1 (Conv2D) (None, None, None, 512) 1180160
block4_conv2 (Conv2D) (None, None, None, 512) 2359808
block4_conv3 (Conv2D) (None, None, None, 512) 2359808
block4_pool (MaxPooling2D) (None, None, None, 512) 0
block5_conv1 (Conv2D) (None, None, None, 512) 2359808
block5_conv2 (Conv2D) (None, None, None, 512) 2359808
block5_conv3 (Conv2D) (None, None, None, 512) 2359808
block5_pool (MaxPooling2D) (None, None, None, 512) 0
=================================================================
Total params: 14,714,688
Trainable params: 0
Non-trainable params: 14,714,688
_________________________________________________________________
conv_base.trainable = True
for layer in conv_base.layers[:-4]:
layer.trainable = False
model_2.summary()
Model: "model_11"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_16 (InputLayer) [(None, 180, 180, 3)] 0
sequential_9 (Sequential) (None, 180, 180, 3) 0
tf.__operators__.getitem_5 (None, 180, 180, 3) 0
(SlicingOpLambda)
tf.nn.bias_add_5 (TFOpLambd (None, 180, 180, 3) 0
a)
vgg16 (Functional) (None, None, None, 512) 14714688
flatten_13 (Flatten) (None, 12800) 0
dense_28 (Dense) (None, 256) 3277056
dropout_13 (Dropout) (None, 256) 0
dense_29 (Dense) (None, 1) 257
=================================================================
Total params: 17,992,001
Trainable params: 10,356,737
Non-trainable params: 7,635,264
_________________________________________________________________
model_2.compile(loss="binary_crossentropy",
optimizer=keras.optimizers.RMSprop(learning_rate=1e-5),
metrics=["accuracy"])
## saving the best model after fine tuning.
callbacks = [
keras.callbacks.ModelCheckpoint(
filepath="./models/fine_tuning.keras",
save_best_only=True,
monitor="val_loss")
]
history = model_2.fit(
train_dataset,
epochs=30,
validation_data=validation_dataset,
callbacks=callbacks)
Epoch 1/30 63/63 [==============================] - 673s 11s/step - loss: 0.8208 - accuracy: 0.9870 - val_loss: 1.6708 - val_accuracy: 0.9830 Epoch 2/30 63/63 [==============================] - 673s 11s/step - loss: 0.2035 - accuracy: 0.9945 - val_loss: 1.7347 - val_accuracy: 0.9830 Epoch 3/30 63/63 [==============================] - 666s 11s/step - loss: 0.1723 - accuracy: 0.9950 - val_loss: 1.4650 - val_accuracy: 0.9860 Epoch 4/30 63/63 [==============================] - 672s 11s/step - loss: 0.2701 - accuracy: 0.9910 - val_loss: 1.5522 - val_accuracy: 0.9860 Epoch 5/30 63/63 [==============================] - 678s 11s/step - loss: 0.3114 - accuracy: 0.9900 - val_loss: 1.8250 - val_accuracy: 0.9850 Epoch 6/30 63/63 [==============================] - 671s 11s/step - loss: 0.3650 - accuracy: 0.9915 - val_loss: 1.5817 - val_accuracy: 0.9820 Epoch 7/30 63/63 [==============================] - 675s 11s/step - loss: 0.2568 - accuracy: 0.9940 - val_loss: 1.4155 - val_accuracy: 0.9810 Epoch 8/30 63/63 [==============================] - 675s 11s/step - loss: 0.1343 - accuracy: 0.9935 - val_loss: 2.4803 - val_accuracy: 0.9750 Epoch 9/30 63/63 [==============================] - 678s 11s/step - loss: 0.2411 - accuracy: 0.9935 - val_loss: 1.5534 - val_accuracy: 0.9840 Epoch 10/30 63/63 [==============================] - 679s 11s/step - loss: 0.1765 - accuracy: 0.9940 - val_loss: 1.5427 - val_accuracy: 0.9810 Epoch 11/30 63/63 [==============================] - 672s 11s/step - loss: 0.1794 - accuracy: 0.9925 - val_loss: 1.5860 - val_accuracy: 0.9830 Epoch 12/30 63/63 [==============================] - 674s 11s/step - loss: 0.3453 - accuracy: 0.9915 - val_loss: 1.6608 - val_accuracy: 0.9810 Epoch 13/30 63/63 [==============================] - 670s 11s/step - loss: 0.1060 - accuracy: 0.9955 - val_loss: 1.7666 - val_accuracy: 0.9790 Epoch 14/30 63/63 [==============================] - 674s 11s/step - loss: 0.2129 - accuracy: 0.9950 - val_loss: 1.6580 - val_accuracy: 0.9830 Epoch 15/30 63/63 [==============================] - 677s 11s/step - loss: 0.2094 - accuracy: 0.9945 - val_loss: 1.8364 - val_accuracy: 0.9780 Epoch 16/30 63/63 [==============================] - 673s 11s/step - loss: 0.1302 - accuracy: 0.9950 - val_loss: 1.5565 - val_accuracy: 0.9810 Epoch 17/30 63/63 [==============================] - 678s 11s/step - loss: 0.0804 - accuracy: 0.9965 - val_loss: 1.4141 - val_accuracy: 0.9810 Epoch 18/30 63/63 [==============================] - 677s 11s/step - loss: 0.1376 - accuracy: 0.9945 - val_loss: 1.2741 - val_accuracy: 0.9840 Epoch 19/30 63/63 [==============================] - 675s 11s/step - loss: 0.1204 - accuracy: 0.9945 - val_loss: 1.3050 - val_accuracy: 0.9850 Epoch 20/30 63/63 [==============================] - 676s 11s/step - loss: 0.0651 - accuracy: 0.9980 - val_loss: 1.3707 - val_accuracy: 0.9840 Epoch 21/30 63/63 [==============================] - 675s 11s/step - loss: 0.2326 - accuracy: 0.9940 - val_loss: 1.4238 - val_accuracy: 0.9830 Epoch 22/30 63/63 [==============================] - 673s 11s/step - loss: 0.0972 - accuracy: 0.9950 - val_loss: 1.4277 - val_accuracy: 0.9830 Epoch 23/30 63/63 [==============================] - 676s 11s/step - loss: 0.0461 - accuracy: 0.9980 - val_loss: 1.5977 - val_accuracy: 0.9810 Epoch 24/30 63/63 [==============================] - 672s 11s/step - loss: 0.2041 - accuracy: 0.9950 - val_loss: 1.5345 - val_accuracy: 0.9810 Epoch 25/30 63/63 [==============================] - 673s 11s/step - loss: 0.0570 - accuracy: 0.9970 - val_loss: 1.9845 - val_accuracy: 0.9780 Epoch 26/30 63/63 [==============================] - 673s 11s/step - loss: 0.1918 - accuracy: 0.9935 - val_loss: 1.5389 - val_accuracy: 0.9850 Epoch 27/30 63/63 [==============================] - 674s 11s/step - loss: 0.0467 - accuracy: 0.9980 - val_loss: 1.4396 - val_accuracy: 0.9870 Epoch 28/30 63/63 [==============================] - 671s 11s/step - loss: 0.0488 - accuracy: 0.9970 - val_loss: 1.9954 - val_accuracy: 0.9830 Epoch 29/30 63/63 [==============================] - 674s 11s/step - loss: 0.0714 - accuracy: 0.9980 - val_loss: 2.0661 - val_accuracy: 0.9800 Epoch 30/30 63/63 [==============================] - 673s 11s/step - loss: 0.0677 - accuracy: 0.9975 - val_loss: 1.5168 - val_accuracy: 0.9850
model_2 = keras.models.load_model("./models/fine_tuning.keras")
test_loss, test_acc = model_2.evaluate(test_dataset)
print(f"Test accuracy: {test_acc:.3f}")
63/63 [==============================] - 426s 7s/step - loss: 1.6183 - accuracy: 0.9760 Test accuracy: 0.976
## plotting validation to test for overfitting
acc = history.history["accuracy"]
val_acc = history.history["val_accuracy"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]
epochs = range(1, len(acc) + 1)
plt.plot(epochs, acc, "bo", label="Training accuracy")
plt.plot(epochs, val_acc, "b", label="Validation accuracy")
plt.title("Training and validation accuracy")
plt.legend()
plt.figure()
plt.plot(epochs, loss, "bo", label="Training loss")
plt.plot(epochs, val_loss, "b", label="Validation loss")
plt.title("Training and validation loss")
plt.legend()
plt.show()
### loading the best models
model = keras.models.load_model(
"./models/convnet_from_scratch_with_augmentation.keras")
test_loss, test_acc = test_model.evaluate(test_dataset)
print(f"Test accuracy for cnn: {test_acc:.3f}")
model_2 = keras.models.load_model("./models/fine_tuning.keras")
test_loss, test_acc = model_2.evaluate(test_dataset)
print(f"Test accuracy for vgg16: {test_acc:.3f}")
63/63 [==============================] - 27s 431ms/step - loss: 0.4094 - accuracy: 0.8185 Test accuracy for cnn: 0.818 63/63 [==============================] - 401s 6s/step - loss: 1.6183 - accuracy: 0.9760 Test accuracy for vgg16: 0.976
import numpy as np
# Unbatch the test dataset for predictions
test_images, test_labels = next(iter(test_dataset.unbatch().batch(len(test_dataset)))) # Load all test data
# Generate predictions for Custom CNN
custom_predictions = (model.predict(test_images) > 0.5).astype("int32")
# Generate predictions for Fine-Tuned VGG16
vgg16_predictions = (model_2.predict(test_images) > 0.5).astype("int32")
2/2 [==============================] - 1s 355ms/step 2/2 [==============================] - 10s 5s/step
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
# Confusion Matrix for Custom CNN
custom_cm = confusion_matrix(test_labels, custom_predictions)
print("Custom CNN - Confusion Matrix:")
print(custom_cm)
ConfusionMatrixDisplay(confusion_matrix=custom_cm, display_labels=["Cat", "Dog"]).plot()
# Confusion Matrix for Fine-Tuned VGG16
vgg16_cm = confusion_matrix(test_labels, vgg16_predictions)
print("VGG16 Fine-Tuned - Confusion Matrix:")
print(vgg16_cm)
ConfusionMatrixDisplay(confusion_matrix=vgg16_cm, display_labels=["Cat", "Dog"]).plot()
Custom CNN - Confusion Matrix: [[25 4] [ 8 26]] VGG16 Fine-Tuned - Confusion Matrix: [[29 0] [ 1 33]]
<sklearn.metrics._plot.confusion_matrix.ConfusionMatrixDisplay at 0x2404efb0b50>
from sklearn.metrics import classification_report
# Classification Report for Custom CNN
print("Custom CNN - Classification Report:")
print(classification_report(test_labels, custom_predictions, target_names=["Cat", "Dog"]))
# Classification Report for Fine-Tuned VGG16
print("VGG16 Fine-Tuned - Classification Report:")
print(classification_report(test_labels, vgg16_predictions, target_names=["Cat", "Dog"]))
Custom CNN - Classification Report:
precision recall f1-score support
Cat 0.76 0.86 0.81 29
Dog 0.87 0.76 0.81 34
accuracy 0.81 63
macro avg 0.81 0.81 0.81 63
weighted avg 0.82 0.81 0.81 63
VGG16 Fine-Tuned - Classification Report:
precision recall f1-score support
Cat 0.97 1.00 0.98 29
Dog 1.00 0.97 0.99 34
accuracy 0.98 63
macro avg 0.98 0.99 0.98 63
weighted avg 0.98 0.98 0.98 63
from sklearn.metrics import precision_recall_curve, auc
import matplotlib.pyplot as plt
# Generate probabilities for Precision-Recall Curve
custom_probs = model.predict(test_images).ravel() # Raw probabilities for Custom CNN
vgg16_probs = model_2.predict(test_images).ravel() # Raw probabilities for VGG16 Fine-Tuned
# Compute Precision-Recall for Custom CNN
custom_precision, custom_recall, _ = precision_recall_curve(test_labels, custom_probs)
custom_pr_auc = auc(custom_recall, custom_precision)
# Compute Precision-Recall for Fine-Tuned VGG16
vgg16_precision, vgg16_recall, _ = precision_recall_curve(test_labels, vgg16_probs)
vgg16_pr_auc = auc(vgg16_recall, vgg16_precision)
# Plot Precision-Recall Curves
plt.figure(figsize=(8, 6))
plt.plot(custom_recall, custom_precision, label=f'Custom CNN (AUC = {custom_pr_auc:.2f})')
plt.plot(vgg16_recall, vgg16_precision, label=f'VGG16 Fine-Tuned (AUC = {vgg16_pr_auc:.2f})')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall Curve')
plt.legend()
plt.grid()
plt.show()
2/2 [==============================] - 1s 491ms/step 2/2 [==============================] - 10s 5s/step
### identifying misclassified samples
# Get indices of misclassified samples for Custom CNN
custom_misclassified_indices = np.where(custom_predictions.ravel() != test_labels)[0]
# Get indices of misclassified samples for Fine-Tuned VGG16
vgg16_misclassified_indices = np.where(vgg16_predictions.ravel() != test_labels)[0]
# Display number of misclassified samples
print(f"Custom CNN - Misclassified Samples: {len(custom_misclassified_indices)}")
print(f"VGG16 Fine-Tuned - Misclassified Samples: {len(vgg16_misclassified_indices)}")
Custom CNN - Misclassified Samples: 12 VGG16 Fine-Tuned - Misclassified Samples: 1
# Function to visualize misclassified samples
def plot_misclassified_samples(images, labels, predictions, misclassified_indices, model_name, num_samples=5):
plt.figure(figsize=(15, 5))
for i, idx in enumerate(misclassified_indices[:num_samples]):
plt.subplot(1, num_samples, i + 1)
plt.imshow(images[idx].numpy().astype("uint8")) # Convert Tensor to NumPy array
plt.title(
f"True: {'Dog' if labels[idx] else 'Cat'}\nPred: {'Dog' if predictions[idx] else 'Cat'}"
)
plt.axis("off")
plt.suptitle(f"{model_name} - Misclassified Samples")
plt.show()
# Visualize misclassified samples for Custom CNN
plot_misclassified_samples(test_images, test_labels, custom_predictions, custom_misclassified_indices, "Custom CNN")
# Visualize misclassified samples for Fine-Tuned VGG16
plot_misclassified_samples(test_images, test_labels, vgg16_predictions, vgg16_misclassified_indices, "Fine-Tuned VGG16")